--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Node / ReticulumProjects / MeshChatX.git / files / meshchatx / src / backend / http / routes / path_probe.py
Displaying Raw • Download
meshchatx/src/backend/http/routes/path_probe.py 4bd787ccd70a459a02eececca3f942f0e64ec4ce (4bd787cc) Text, 21.48 KB
T8b949e# SPDX-License-Identifier: 0BSD
T8b949e"""HTTP routes: path_probe."""
Tff7b72from T7ee787__future__ Tff7b72import Te6edf3annotations
Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backendT7ee787.T7ee787httpT7ee787.T7ee787meshchat_names Tff7b72import Tb4b4b4( T8b949e# noqa: F401
Te6edf3GeoValidationErrorTb4b4b4,
Te6edf3OutboundHttpBlockedErrorTb4b4b4,
Te6edf3OverlayExportErrorTb4b4b4,
Te6edf3OverlaySourceParseErrorTb4b4b4,
Te6edf3PluginSecurityErrorTb4b4b4,
Te6edf3AsyncUtilsTb4b4b4,
Te6edf3InterfaceConfigParserTb4b4b4,
Te6edf3InterfaceDiscoveryTb4b4b4,
Te6edf3InterfaceEditorTb4b4b4,
Te6edf3LOGIN_PATHTb4b4b4,
Te6edf3LXMFTb4b4b4,
Te6edf3LxmfAudioFieldTb4b4b4,
Te6edf3LxmfFileAttachmentTb4b4b4,
Te6edf3LxmfFileAttachmentsFieldTb4b4b4,
Te6edf3LxmfImageFieldTb4b4b4,
Te6edf3MAX_EXPORT_TILESTb4b4b4,
Te6edf3MarkdownRendererTb4b4b4,
Te6edf3NomadnetFileDownloaderTb4b4b4,
Te6edf3NomadnetPageDownloaderTb4b4b4,
Te6edf3RNProbeHandlerTb4b4b4,
Te6edf3RNSTb4b4b4,
Te6edf3ReticulumMeshChatTb4b4b4,
Te6edf3SETUP_PATHTb4b4b4,
Te6edf3TRANSPARENT_TILETb4b4b4,
Te6edf3TelemeterTb4b4b4,
Te6edf3UTCTb4b4b4,
Te6edf3WSMsgTypeTb4b4b4,
Te6edf3_is_chaquopy_androidTb4b4b4,
Te6edf3_is_loopback_bind_hostTb4b4b4,
Te6edf3_request_client_ipTb4b4b4,
Te6edf3aiohttpTb4b4b4,
Te6edf3app_versionTb4b4b4,
Te6edf3assert_migration_context_pathsTb4b4b4,
Te6edf3asyncioTb4b4b4,
Te6edf3base64Tb4b4b4,
Te6edf3bcryptTb4b4b4,
Te6edf3binasciiTb4b4b4,
Te6edf3build_blocklist_export_documentTb4b4b4,
Te6edf3build_export_documentTb4b4b4,
Te6edf3build_messages_export_bundleTb4b4b4,
Te6edf3cache_statsTb4b4b4,
Te6edf3cancel_inbound_deliveriesTb4b4b4,
Te6edf3castTb4b4b4,
Te6edf3compute_lxmf_conversation_unread_from_latest_rowTb4b4b4,
Te6edf3configparserTb4b4b4,
Te6edf3contextlibTb4b4b4,
Te6edf3convert_db_favourite_to_dictTb4b4b4,
Te6edf3convert_db_lxmf_message_to_dictTb4b4b4,
Te6edf3convert_lxmf_message_to_dictTb4b4b4,
Te6edf3convert_nomadnet_field_data_to_mapTb4b4b4,
Te6edf3convert_nomadnet_string_data_to_mapTb4b4b4,
Te6edf3convert_propagation_node_state_to_stringTb4b4b4,
Te6edf3copyTb4b4b4,
Te6edf3datetimeTb4b4b4,
Te6edf3describe_port_conflictTb4b4b4,
Te6edf3detect_image_format_from_magicTb4b4b4,
Te6edf3ensure_outbound_http_allowedTb4b4b4,
Te6edf3ensure_session_csrf_tokenTb4b4b4,
Te6edf3filter_announced_dicts_by_search_queryTb4b4b4,
Te6edf3fresh_storage_at_targetTb4b4b4,
Te6edf3get_cached_active_linkTb4b4b4,
Te6edf3get_file_pathTb4b4b4,
Te6edf3get_sessionTb4b4b4,
Te6edf3get_trusted_proxy_cidrsTb4b4b4,
Te6edf3gif_utilsTb4b4b4,
Te6edf3i2p_supportTb4b4b4,
Te6edf3import_messages_export_bundleTb4b4b4,
Te6edf3ioTb4b4b4,
Te6edf3is_mbtiles_filenameTb4b4b4,
Te6edf3is_path_within_dirTb4b4b4,
Te6edf3is_port_in_useTb4b4b4,
Te6edf3is_user_facing_lxmf_payloadTb4b4b4,
Te6edf3jsonTb4b4b4,
Te6edf3list_host_network_interfacesTb4b4b4,
Te6edf3list_inbound_deliveriesTb4b4b4,
Te6edf3list_portsTb4b4b4,
Te6edf3load_app_security_settingsTb4b4b4,
Te6edf3loggerTb4b4b4,
Te6edf3loggingTb4b4b4,
Te6edf3lxmf_sidebar_preview_for_conversation_latest_rowTb4b4b4,
Te6edf3memory_log_handlerTb4b4b4,
Te6edf3message_fields_have_attachmentsTb4b4b4,
Te6edf3migrate_legacy_to_targetTb4b4b4,
Te6edf3mime_for_image_typeTb4b4b4,
Te6edf3normalize_identity_storage_hashTb4b4b4,
Te6edf3normalize_lxmf_sieve_filtersTb4b4b4,
Te6edf3normalize_message_blocklistTb4b4b4,
Te6edf3osTb4b4b4,
Te6edf3parse_bool_query_paramTb4b4b4,
Te6edf3parse_import_documentTb4b4b4,
Te6edf3parse_lxmf_display_nameTb4b4b4,
Te6edf3parse_lxmf_propagation_node_app_dataTb4b4b4,
Te6edf3parse_lxmf_sieve_filters_jsonTb4b4b4,
Te6edf3parse_lxmf_stamp_costTb4b4b4,
Te6edf3parse_message_blocklist_jsonTb4b4b4,
Te6edf3parse_nomadnetwork_node_display_nameTb4b4b4,
Te6edf3platformTb4b4b4,
Te6edf3privacy_mode_enabledTb4b4b4,
Te6edf3psutilTb4b4b4,
Te6edf3purge_messages_before_cutoffTb4b4b4,
Te6edf3reTb4b4b4,
Te6edf3resolve_message_age_cutoffTb4b4b4,
Te6edf3reticulum_pathfindingTb4b4b4,
Te6edf3rotate_session_csrf_tokenTb4b4b4,
Te6edf3rrc_protocolTb4b4b4,
Te6edf3safe_path_under_dirTb4b4b4,
Te6edf3sanitize_sticker_emojiTb4b4b4,
Te6edf3sanitize_sticker_nameTb4b4b4,
Te6edf3sanitize_websocket_config_updateTb4b4b4,
Te6edf3save_app_security_settingsTb4b4b4,
Te6edf3secretsTb4b4b4,
Te6edf3shutilTb4b4b4,
Te6edf3sqlite3Tb4b4b4,
Te6edf3sticker_pack_utilsTb4b4b4,
Te6edf3sysTb4b4b4,
Te6edf3tempfileTb4b4b4,
Te6edf3threadingTb4b4b4,
Te6edf3timeTb4b4b4,
Te6edf3tracebackTb4b4b4,
Te6edf3user_agent_hashTb4b4b4,
Te6edf3validate_export_documentTb4b4b4,
Te6edf3webTb4b4b4,
Te6edf3websocket_type_requires_authTb4b4b4,
Te6edf3zipfileTb4b4b4,
Tb4b4b4)
Tff7b72def Td2a8ffregister_path_probe_routesTb4b4b4(Te6edf3routesTb4b4b4, Te6edf3appTb4b4b4)Tb4b4b4:
T8b949e# get path to destination
Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/destination/Tffd700{destination_hash}Ta5d6ff/pathTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffdestination_pathTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
T8b949e# get path params
Te6edf3destination_hash Tff7b72= Te6edf3requestTff7b72.Td2a8ffmatch_infoTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffdestination_hashTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff"Tb4b4b4)
T8b949e# convert destination hash to bytes
Te6edf3destination_hash Tff7b72= Tffa657bytesTff7b72.Td2a8fffromhexTb4b4b4(Te6edf3destination_hashTb4b4b4)
Te6edf3destination_hash_hex Tff7b72= Te6edf3destination_hashTff7b72.Td2a8ffhexTb4b4b4(Tb4b4b4)
Te6edf3local_hashesTb4b4b4: Tffa657setTb4b4b4[Tffa657strTb4b4b4] Tff7b72= Tffa657setTb4b4b4(Tb4b4b4)
Tff7b72with Te6edf3contextlibTff7b72.Td2a8ffsuppressTb4b4b4(Tf85149ExceptionTb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3appTff7b72.Td2a8ffcurrent_context Tff7b72and Te6edf3appTff7b72.Td2a8ffcurrent_contextTff7b72.Td2a8ffidentityTb4b4b4:
Te6edf3local_hashesTff7b72.Td2a8ffaddTb4b4b4(Te6edf3appTff7b72.Td2a8ffcurrent_contextTff7b72.Td2a8ffidentityTff7b72.Td2a8ffhashTff7b72.Td2a8ffhexTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72with Te6edf3contextlibTff7b72.Td2a8ffsuppressTb4b4b4(Tf85149ExceptionTb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3appTff7b72.Td2a8fflocal_lxmf_destination Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4:
Te6edf3local_hashesTff7b72.Td2a8ffaddTb4b4b4(Te6edf3appTff7b72.Td2a8fflocal_lxmf_destinationTff7b72.Td2a8ffhashTff7b72.Td2a8ffhexTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72with Te6edf3contextlibTff7b72.Td2a8ffsuppressTb4b4b4(Tf85149ExceptionTb4b4b4)Tb4b4b4:
Tff7b72if Te6edf3appTff7b72.Td2a8ffcurrent_context Tff7b72and Te6edf3appTff7b72.Td2a8ffcurrent_contextTff7b72.Td2a8ffmessage_routerTb4b4b4:
Te6edf3pdest Tff7b72= Te6edf3appTff7b72.Td2a8ffcurrent_contextTff7b72.Td2a8ffmessage_routerTff7b72.Td2a8ffpropagation_destination
Tff7b72if Te6edf3pdest Tff7b72is Tff7b72not Tff7b72None Tff7b72and Tffa657getattrTb4b4b4(Te6edf3pdestTb4b4b4, Ta5d6ff"Ta5d6ffhashTa5d6ff"Tb4b4b4, Tff7b72NoneTb4b4b4)Tb4b4b4:
Te6edf3local_hashesTff7b72.Td2a8ffaddTb4b4b4(Te6edf3pdestTff7b72.Td2a8ffhashTff7b72.Td2a8ffhexTb4b4b4(Tb4b4b4)Tb4b4b4)
Tff7b72if Te6edf3destination_hash_hex Tff7b72in Te6edf3local_hashesTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffpathTa5d6ff"Tb4b4b4: Tb4b4b4{
Ta5d6ff"Ta5d6ffhopsTa5d6ff"Tb4b4b4: T79c0ff0Tb4b4b4,
Ta5d6ff"Ta5d6ffnext_hopTa5d6ff"Tb4b4b4: Te6edf3destination_hash_hexTb4b4b4,
Ta5d6ff"Ta5d6ffnext_hop_interfaceTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffLocalTa5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Ta5d6ff"Ta5d6ffpath_staleTa5d6ff"Tb4b4b4: Tff7b72FalseTb4b4b4,
Ta5d6ff"Ta5d6ffpath_unresponsiveTa5d6ff"Tb4b4b4: Tff7b72FalseTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
T8b949e# check if user wants to request the path from the network right now
Te6edf3request_query_param Tff7b72= Te6edf3requestTff7b72.Td2a8ffqueryTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffrequestTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6fffalseTa5d6ff"Tb4b4b4)
Te6edf3should_request_now Tff7b72= Te6edf3request_query_param Tff7b72in Tb4b4b4(Ta5d6ff"Ta5d6fftrueTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff1Ta5d6ff"Tb4b4b4)
Tff7b72if Te6edf3should_request_nowTb4b4b4:
T8b949e# determine how long we should wait for a path response
Te6edf3timeout_seconds Tff7b72= Tffa657intTb4b4b4(Te6edf3requestTff7b72.Td2a8ffqueryTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fftimeoutTa5d6ff"Tb4b4b4, T79c0ff15Tb4b4b4)Tb4b4b4)
Te6edf3timeout_after_seconds Tff7b72= Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4) Tff7b72+ Te6edf3timeout_seconds
Te6edf3reticulum Tff7b72= Te6edf3appTff7b72.Td2a8ffreticulum Tff7b72if Tffa657hasattrTb4b4b4(Te6edf3appTb4b4b4, Ta5d6ff"Ta5d6ffreticulumTa5d6ff"Tb4b4b4) Tff7b72else Tff7b72None
Te6edf3reticulum_pathfindingTff7b72.Td2a8ffprepare_fresh_path_requestTb4b4b4(
Te6edf3reticulumTb4b4b4,
Te6edf3destination_hashTb4b4b4,
Tb4b4b4)
T8b949e# wait until we have a path, or give up after the configured timeout
Tff7b72while Tb4b4b4(
Tff7b72not Te6edf3RNSTff7b72.Td2a8ffTransportTff7b72.Td2a8ffhas_pathTb4b4b4(Te6edf3destination_hashTb4b4b4)
Tff7b72and Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4) Tff7b72< Te6edf3timeout_after_seconds
Tb4b4b4)Tb4b4b4:
Tff7b72await Te6edf3asyncioTff7b72.Td2a8ffsleepTb4b4b4(T79c0ff0.1Tb4b4b4)
T8b949e# ensure path is known
Tff7b72if Tff7b72not Te6edf3RNSTff7b72.Td2a8ffTransportTff7b72.Td2a8ffhas_pathTb4b4b4(Te6edf3destination_hashTb4b4b4)Tb4b4b4:
Te6edf3pm Tff7b72= Te6edf3reticulum_pathfindingTff7b72.Td2a8ffpath_metadata_for_apiTb4b4b4(Te6edf3destination_hashTb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffpathTa5d6ff"Tb4b4b4: Tff7b72NoneTb4b4b4,
Tff7b72*Tff7b72*Te6edf3pmTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
T8b949e# determine next hop and hop count
Te6edf3hops Tff7b72= Te6edf3RNSTff7b72.Td2a8ffTransportTff7b72.Td2a8ffhops_toTb4b4b4(Te6edf3destination_hashTb4b4b4)
Tff7b72if Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3hopsTb4b4b4, Tffa657intTb4b4b4)Tb4b4b4:
Te6edf3pm Tff7b72= Te6edf3reticulum_pathfindingTff7b72.Td2a8ffpath_metadata_for_apiTb4b4b4(Te6edf3destination_hashTb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffpathTa5d6ff"Tb4b4b4: Tff7b72NoneTb4b4b4,
Tff7b72*Tff7b72*Te6edf3pmTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Te6edf3next_hop_bytes Tff7b72= Tff7b72None
Tff7b72if Tffa657hasattrTb4b4b4(Te6edf3appTb4b4b4, Ta5d6ff"Ta5d6ffreticulumTa5d6ff"Tb4b4b4) Tff7b72and Te6edf3appTff7b72.Td2a8ffreticulumTb4b4b4:
Te6edf3next_hop_bytes Tff7b72= Te6edf3appTff7b72.Td2a8ffreticulumTff7b72.Td2a8ffget_next_hopTb4b4b4(Te6edf3destination_hashTb4b4b4)
Tff7b72if Te6edf3next_hop_bytes Tff7b72is Tff7b72not Tff7b72None Tff7b72and Tff7b72not Tffa657isinstanceTb4b4b4(
Te6edf3next_hop_bytesTb4b4b4,
Tb4b4b4(Tffa657bytesTb4b4b4, Tffa657bytearrayTb4b4b4)Tb4b4b4,
Tb4b4b4)Tb4b4b4:
Te6edf3next_hop_bytes Tff7b72= Tff7b72None
T8b949e# ensure next hop provided
Tff7b72if Te6edf3next_hop_bytes Tff7b72is Tff7b72NoneTb4b4b4:
Te6edf3pm Tff7b72= Te6edf3reticulum_pathfindingTff7b72.Td2a8ffpath_metadata_for_apiTb4b4b4(Te6edf3destination_hashTb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffpathTa5d6ff"Tb4b4b4: Tff7b72NoneTb4b4b4,
Tff7b72*Tff7b72*Te6edf3pmTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
Te6edf3next_hop Tff7b72= Te6edf3next_hop_bytesTff7b72.Td2a8ffhexTb4b4b4(Tb4b4b4)
Te6edf3next_hop_interface Tff7b72= Tb4b4b4(
Te6edf3appTff7b72.Td2a8ffreticulumTff7b72.Td2a8ffget_next_hop_if_nameTb4b4b4(Te6edf3destination_hashTb4b4b4)
Tff7b72if Tffa657hasattrTb4b4b4(Te6edf3appTb4b4b4, Ta5d6ff"Ta5d6ffreticulumTa5d6ff"Tb4b4b4) Tff7b72and Te6edf3appTff7b72.Td2a8ffreticulum
Tff7b72else Tff7b72None
Tb4b4b4)
Te6edf3pm Tff7b72= Te6edf3reticulum_pathfindingTff7b72.Td2a8ffpath_metadata_for_apiTb4b4b4(Te6edf3destination_hashTb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffpathTa5d6ff"Tb4b4b4: Tb4b4b4{
Ta5d6ff"Ta5d6ffhopsTa5d6ff"Tb4b4b4: Te6edf3hopsTb4b4b4,
Ta5d6ff"Ta5d6ffnext_hopTa5d6ff"Tb4b4b4: Te6edf3next_hopTb4b4b4,
Ta5d6ff"Ta5d6ffnext_hop_interfaceTa5d6ff"Tb4b4b4: Te6edf3next_hop_interfaceTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tff7b72*Tff7b72*Te6edf3pmTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
T8b949e# drop path to destination
T8b949e# drop path to destination
Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/destination/Tffd700{destination_hash}Ta5d6ff/drop-pathTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffdestination_drop_pathTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
T8b949e# get path params
Te6edf3destination_hash Tff7b72= Te6edf3requestTff7b72.Td2a8ffmatch_infoTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffdestination_hashTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff"Tb4b4b4)
T8b949e# convert destination hash to bytes
Te6edf3destination_hash Tff7b72= Tffa657bytesTff7b72.Td2a8fffromhexTb4b4b4(Te6edf3destination_hashTb4b4b4)
T8b949e# drop path
Tff7b72if Tffa657hasattrTb4b4b4(Te6edf3appTb4b4b4, Ta5d6ff"Ta5d6ffreticulumTa5d6ff"Tb4b4b4) Tff7b72and Te6edf3appTff7b72.Td2a8ffreticulumTb4b4b4:
Te6edf3appTff7b72.Td2a8ffreticulumTff7b72.Td2a8ffdrop_pathTb4b4b4(Te6edf3destination_hashTb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffPath has been droppedTa5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
T8b949e# proactively ask Reticulum to resolve or refresh path (non-blocking HTTP, and discovery runs in background)
T8b949e# proactively ask Reticulum to resolve or refresh path (non-blocking HTTP, and discovery runs in background)
Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/destination/Tffd700{destination_hash}Ta5d6ff/request-pathTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffdestination_request_path_fireTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Te6edf3destination_hash Tff7b72= Te6edf3requestTff7b72.Td2a8ffmatch_infoTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffdestination_hashTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff"Tb4b4b4)
Tff7b72tryTb4b4b4:
Te6edf3destination_hash_bytes Tff7b72= Tffa657bytesTff7b72.Td2a8fffromhexTb4b4b4(Te6edf3destination_hashTb4b4b4)
Tff7b72except Tf85149ExceptionTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffinvalid destination hashTa5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)
Te6edf3reticulum Tff7b72= Te6edf3appTff7b72.Td2a8ffreticulum Tff7b72if Tffa657hasattrTb4b4b4(Te6edf3appTb4b4b4, Ta5d6ff"Ta5d6ffreticulumTa5d6ff"Tb4b4b4) Tff7b72else Tff7b72None
Te6edf3reticulum_pathfindingTff7b72.Td2a8ffprepare_fresh_path_requestTb4b4b4(
Te6edf3reticulumTb4b4b4,
Te6edf3destination_hash_bytesTb4b4b4,
Tb4b4b4)
T8b949e# if path is already available, resend failed messages for this destination
Tff7b72if Te6edf3RNSTff7b72.Td2a8ffTransportTff7b72.Td2a8ffhas_pathTb4b4b4(Te6edf3destination_hash_bytesTb4b4b4)Tb4b4b4:
Tff7b72for Te6edf3_ctx Tff7b72in Tffa657listTb4b4b4(Te6edf3appTff7b72.Td2a8ffcontextsTff7b72.Td2a8ffvaluesTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4:
Tff7b72if Tb4b4b4(
Te6edf3_ctxTff7b72.Td2a8ffrunning
Tff7b72and Te6edf3_ctxTff7b72.Td2a8ffconfigTff7b72.Td2a8ffauto_resend_failed_messages_when_announce_receivedTff7b72.Td2a8ffgetTb4b4b4(Tb4b4b4)
Tb4b4b4)Tb4b4b4:
Te6edf3AsyncUtilsTff7b72.Td2a8ffrun_asyncTb4b4b4(
Te6edf3appTff7b72.Td2a8ffresend_failed_messages_for_destinationTb4b4b4(
Te6edf3destination_hashTb4b4b4,
Te6edf3contextTff7b72=Te6edf3_ctxTb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffokTa5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
T8b949e# get signal metrics for a destination by checking the latest announce or lxmf message received from them
T8b949e# get signal metrics for a destination by checking the latest announce or lxmf message received from them
Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/destination/Tffd700{destination_hash}Ta5d6ff/signal-metricsTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffdestination_signal_metricsTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
T8b949e# get path params
Te6edf3destination_hash Tff7b72= Te6edf3requestTff7b72.Td2a8ffmatch_infoTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffdestination_hashTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff"Tb4b4b4)
T8b949e# signal metrics to return
Te6edf3snr Tff7b72= Tff7b72None
Te6edf3rssi Tff7b72= Tff7b72None
Te6edf3quality Tff7b72= Tff7b72None
Te6edf3updated_at Tff7b72= Tff7b72None
T8b949e# get latest announce from database for the provided destination hash
Te6edf3latest_announce Tff7b72= Te6edf3appTff7b72.Td2a8ffdatabaseTff7b72.Td2a8ffannouncesTff7b72.Td2a8ffget_announce_by_hashTb4b4b4(
Te6edf3destination_hashTb4b4b4,
Tb4b4b4)
T8b949e# get latest lxmf message from database sent to us from the provided destination hash
Te6edf3local_hash Tff7b72= Te6edf3appTff7b72.Td2a8fflocal_lxmf_destinationTff7b72.Td2a8ffhexhash
Te6edf3messages Tff7b72= Te6edf3appTff7b72.Td2a8ffmessage_handlerTff7b72.Td2a8ffget_conversation_messagesTb4b4b4(
Te6edf3local_hashTb4b4b4,
Te6edf3destination_hashTb4b4b4,
Te6edf3limitTff7b72=T79c0ff1Tb4b4b4,
Tb4b4b4)
T8b949e# Filter for incoming messages only
Te6edf3latest_lxmf_message Tff7b72= Tffa657nextTb4b4b4(
Tb4b4b4(Te6edf3m Tff7b72for Te6edf3m Tff7b72in Te6edf3messages Tff7b72if Te6edf3mTb4b4b4[Ta5d6ff"Ta5d6ffsource_hashTa5d6ff"Tb4b4b4] Tff7b72== Te6edf3destination_hashTb4b4b4)Tb4b4b4,
Tff7b72NoneTb4b4b4,
Tb4b4b4)
T8b949e# determine when latest announce was received
Te6edf3latest_announce_at Tff7b72= Tff7b72None
Tff7b72if Te6edf3latest_announce Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4:
Te6edf3latest_announce_at Tff7b72= Te6edf3datetimeTff7b72.Td2a8fffromisoformatTb4b4b4(
Te6edf3latest_announceTb4b4b4[Ta5d6ff"Ta5d6ffupdated_atTa5d6ff"Tb4b4b4]Tb4b4b4,
Tb4b4b4)
Tff7b72if Te6edf3latest_announce_atTff7b72.Td2a8fftzinfo Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4:
Te6edf3latest_announce_at Tff7b72= Te6edf3latest_announce_atTff7b72.Td2a8ffreplaceTb4b4b4(Te6edf3tzinfoTff7b72=Tff7b72NoneTb4b4b4)
T8b949e# determine when latest lxmf message was received
Te6edf3latest_lxmf_message_at Tff7b72= Tff7b72None
Tff7b72if Te6edf3latest_lxmf_message Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4:
Te6edf3latest_lxmf_message_at Tff7b72= Te6edf3datetimeTff7b72.Td2a8fffromisoformatTb4b4b4(
Te6edf3latest_lxmf_messageTb4b4b4[Ta5d6ff"Ta5d6ffcreated_atTa5d6ff"Tb4b4b4]Tb4b4b4,
Tb4b4b4)
Tff7b72if Te6edf3latest_lxmf_message_atTff7b72.Td2a8fftzinfo Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4:
Te6edf3latest_lxmf_message_at Tff7b72= Te6edf3latest_lxmf_message_atTff7b72.Td2a8ffreplaceTb4b4b4(Te6edf3tzinfoTff7b72=Tff7b72NoneTb4b4b4)
T8b949e# get signal metrics from latest announce
Tff7b72if Te6edf3latest_announce Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4:
Te6edf3snr Tff7b72= Te6edf3latest_announceTb4b4b4[Ta5d6ff"Ta5d6ffsnrTa5d6ff"Tb4b4b4]
Te6edf3rssi Tff7b72= Te6edf3latest_announceTb4b4b4[Ta5d6ff"Ta5d6ffrssiTa5d6ff"Tb4b4b4]
Te6edf3quality Tff7b72= Te6edf3latest_announceTb4b4b4[Ta5d6ff"Ta5d6ffqualityTa5d6ff"Tb4b4b4]
T8b949e# using updated_at from announce because this is when the latest announce was received
Te6edf3updated_at Tff7b72= Te6edf3latest_announceTb4b4b4[Ta5d6ff"Ta5d6ffupdated_atTa5d6ff"Tb4b4b4]
T8b949e# get signal metrics from latest lxmf message if it's more recent than the announce
Tff7b72if Te6edf3latest_lxmf_message Tff7b72is Tff7b72not Tff7b72None Tff7b72and Tb4b4b4(
Te6edf3latest_announce_at Tff7b72is Tff7b72None Tff7b72or Te6edf3latest_lxmf_message_at Tff7b72> Te6edf3latest_announce_at
Tb4b4b4)Tb4b4b4:
Te6edf3snr Tff7b72= Te6edf3latest_lxmf_messageTb4b4b4[Ta5d6ff"Ta5d6ffsnrTa5d6ff"Tb4b4b4]
Te6edf3rssi Tff7b72= Te6edf3latest_lxmf_messageTb4b4b4[Ta5d6ff"Ta5d6ffrssiTa5d6ff"Tb4b4b4]
Te6edf3quality Tff7b72= Te6edf3latest_lxmf_messageTb4b4b4[Ta5d6ff"Ta5d6ffqualityTa5d6ff"Tb4b4b4]
T8b949e# using created_at from lxmf message because this is when the message was received
Te6edf3updated_at Tff7b72= Te6edf3latest_lxmf_messageTb4b4b4[Ta5d6ff"Ta5d6ffcreated_atTa5d6ff"Tb4b4b4]
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffsignal_metricsTa5d6ff"Tb4b4b4: Tb4b4b4{
Ta5d6ff"Ta5d6ffsnrTa5d6ff"Tb4b4b4: Te6edf3snrTb4b4b4,
Ta5d6ff"Ta5d6ffrssiTa5d6ff"Tb4b4b4: Te6edf3rssiTb4b4b4,
Ta5d6ff"Ta5d6ffqualityTa5d6ff"Tb4b4b4: Te6edf3qualityTb4b4b4,
Ta5d6ff"Ta5d6ffupdated_atTa5d6ff"Tb4b4b4: Te6edf3updated_atTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
T8b949e# pings an lxmf.delivery destination by sending empty data and waiting for the recipient to send a proof back
T8b949e# the lxmf router proves all received packets, then drops them if they can't be decoded as lxmf messages
T8b949e# this allows us to ping/probe any active lxmf.delivery destination and get rtt/snr/rssi data on demand
T8b949e# https://github.com/markqvist/LXMF/blob/9ff76c0473e9d4107e079f266dd08144bb74c7c8/LXMF/LXMRouter.py#L234
T8b949e# https://github.com/markqvist/LXMF/blob/9ff76c0473e9d4107e079f266dd08144bb74c7c8/LXMF/LXMRouter.py#L1374
T8b949e# pings an lxmf.delivery destination by sending empty data and waiting for the recipient to send a proof back
T8b949e# the lxmf router proves all received packets, then drops them if they can't be decoded as lxmf messages
T8b949e# this allows us to ping/probe any active lxmf.delivery destination and get rtt/snr/rssi data on demand
T8b949e# https://github.com/markqvist/LXMF/blob/9ff76c0473e9d4107e079f266dd08144bb74c7c8/LXMF/LXMRouter.py#L234
T8b949e# https://github.com/markqvist/LXMF/blob/9ff76c0473e9d4107e079f266dd08144bb74c7c8/LXMF/LXMRouter.py#L1374
Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/ping/Tffd700{destination_hash}Ta5d6ff/lxmf.deliveryTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffping_lxmf_deliveryTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
T8b949e# get path params
Te6edf3destination_hash_str Tff7b72= Te6edf3requestTff7b72.Td2a8ffmatch_infoTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffdestination_hashTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ff"Tb4b4b4)
Tff7b72tryTb4b4b4:
Te6edf3destination_hash Tff7b72= Tffa657bytesTff7b72.Td2a8fffromhexTb4b4b4(Te6edf3destination_hash_strTb4b4b4)
Tff7b72except Tf85149ExceptionTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffPing failed. Invalid destination hash.Ta5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)
Tff7b72tryTb4b4b4:
Te6edf3timeout_seconds Tff7b72= Tffa657intTb4b4b4(Te6edf3requestTff7b72.Td2a8ffqueryTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fftimeoutTa5d6ff"Tb4b4b4, T79c0ff15Tb4b4b4)Tb4b4b4)
Tff7b72except Tb4b4b4(Tf85149TypeErrorTb4b4b4, Tf85149ValueErrorTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffPing failed. Timeout must be an integer.Ta5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)
Tff7b72if Te6edf3timeout_seconds Tff7b72< T79c0ff1Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffPing failed. Timeout must be at least 1 second.Ta5d6ff"Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff400Tb4b4b4,
Tb4b4b4)
T8b949e# Split the budget so path discovery cannot consume the whole timeout.
Te6edf3path_budget_seconds Tff7b72= Tffa657maxTb4b4b4(T79c0ff1Tb4b4b4, Te6edf3timeout_seconds Tff7b72/Tff7b72/ T79c0ff2Tb4b4b4)
Te6edf3delivery_budget_seconds Tff7b72= Tffa657maxTb4b4b4(T79c0ff1Tb4b4b4, Te6edf3timeout_seconds Tff7b72- Te6edf3path_budget_secondsTb4b4b4)
Te6edf3path_deadline Tff7b72= Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4) Tff7b72+ Te6edf3path_budget_seconds
T8b949e# request path if we don't have it
Tff7b72if Tff7b72not Te6edf3RNSTff7b72.Td2a8ffTransportTff7b72.Td2a8ffhas_pathTb4b4b4(Te6edf3destination_hashTb4b4b4)Tb4b4b4:
Te6edf3RNSTff7b72.Td2a8ffTransportTff7b72.Td2a8ffrequest_pathTb4b4b4(Te6edf3destination_hashTb4b4b4)
T8b949e# wait until we have a path, or give up after the path budget
Tff7b72while Tb4b4b4(
Tff7b72not Te6edf3RNSTff7b72.Td2a8ffTransportTff7b72.Td2a8ffhas_pathTb4b4b4(Te6edf3destination_hashTb4b4b4) Tff7b72and Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4) Tff7b72< Te6edf3path_deadline
Tb4b4b4)Tb4b4b4:
Tff7b72await Te6edf3asyncioTff7b72.Td2a8ffsleepTb4b4b4(T79c0ff0.1Tb4b4b4)
Tff7b72if Tff7b72not Te6edf3RNSTff7b72.Td2a8ffTransportTff7b72.Td2a8ffhas_pathTb4b4b4(Te6edf3destination_hashTb4b4b4)Tb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffPing failed. Could not find path to destination.Ta5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff503Tb4b4b4,
Tb4b4b4)
T8b949e# find destination identity (pass string hash, not bytes)
Te6edf3destination_identity Tff7b72= Te6edf3appTff7b72.Td2a8ffrecall_identityTb4b4b4(Te6edf3destination_hash_strTb4b4b4)
Tff7b72if Te6edf3destination_identity Tff7b72is Tff7b72NoneTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6ff"Ta5d6ffPing failed. Could not recall destination identity.Ta5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff503Tb4b4b4,
Tb4b4b4)
T8b949e# create outbound destination
Te6edf3request_destination Tff7b72= Te6edf3RNSTff7b72.Td2a8ffDestinationTb4b4b4(
Te6edf3destination_identityTb4b4b4,
Te6edf3RNSTff7b72.Td2a8ffDestinationTff7b72.Td2a8ffOUTTb4b4b4,
Te6edf3RNSTff7b72.Td2a8ffDestinationTff7b72.Td2a8ffSINGLETb4b4b4,
Ta5d6ff"Ta5d6fflxmfTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffdeliveryTa5d6ff"Tb4b4b4,
Tb4b4b4)
T8b949e# send empty packet to destination
Te6edf3packet Tff7b72= Te6edf3RNSTff7b72.Td2a8ffPacketTb4b4b4(Te6edf3request_destinationTb4b4b4, Ta5d6ffbTa5d6ff"Ta5d6ff"Tb4b4b4)
Te6edf3receipt Tff7b72= Te6edf3packetTff7b72.Td2a8ffsendTb4b4b4(Tb4b4b4)
Te6edf3delivery_deadline Tff7b72= Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4) Tff7b72+ Te6edf3delivery_budget_seconds
T8b949e# wait until delivered, or give up after the delivery budget
Tff7b72while Tb4b4b4(
Te6edf3receiptTff7b72.Td2a8ffstatus Tff7b72!= Te6edf3RNSTff7b72.Td2a8ffPacketReceiptTff7b72.Td2a8ffDELIVERED
Tff7b72and Te6edf3timeTff7b72.Td2a8fftimeTb4b4b4(Tb4b4b4) Tff7b72< Te6edf3delivery_deadline
Tb4b4b4)Tb4b4b4:
Tff7b72await Te6edf3asyncioTff7b72.Td2a8ffsleepTb4b4b4(T79c0ff0.1Tb4b4b4)
T8b949e# ping failed if not delivered
Tff7b72if Te6edf3receiptTff7b72.Td2a8ffstatus Tff7b72!= Te6edf3RNSTff7b72.Td2a8ffPacketReceiptTff7b72.Td2a8ffDELIVEREDTb4b4b4:
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6fffTa5d6ff"Ta5d6ffPing failed. Timed out after Tffd700{Te6edf3timeout_secondsTffd700}Ta5d6ff seconds.Ta5d6ff"Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Te6edf3statusTff7b72=T79c0ff503Tb4b4b4,
Tb4b4b4)
T8b949e# get number of hops to destination and back from destination
Te6edf3hops_there Tff7b72= Te6edf3RNSTff7b72.Td2a8ffTransportTff7b72.Td2a8ffhops_toTb4b4b4(Te6edf3destination_hashTb4b4b4)
Te6edf3hops_back Tff7b72= Te6edf3receiptTff7b72.Td2a8ffproof_packetTff7b72.Td2a8ffhops
T8b949e# get rssi
Te6edf3rssi Tff7b72= Te6edf3receiptTff7b72.Td2a8ffproof_packetTff7b72.Td2a8ffrssi
Tff7b72if Te6edf3rssi Tff7b72is Tff7b72None Tff7b72and Tffa657hasattrTb4b4b4(Te6edf3appTb4b4b4, Ta5d6ff"Ta5d6ffreticulumTa5d6ff"Tb4b4b4) Tff7b72and Te6edf3appTff7b72.Td2a8ffreticulumTb4b4b4:
Te6edf3rssi Tff7b72= Te6edf3appTff7b72.Td2a8ffreticulumTff7b72.Td2a8ffget_packet_rssiTb4b4b4(Te6edf3receiptTff7b72.Td2a8ffproof_packetTff7b72.Td2a8ffpacket_hashTb4b4b4)
T8b949e# get snr
Te6edf3snr Tff7b72= Te6edf3receiptTff7b72.Td2a8ffproof_packetTff7b72.Td2a8ffsnr
Tff7b72if Te6edf3snr Tff7b72is Tff7b72None Tff7b72and Tffa657hasattrTb4b4b4(Te6edf3appTb4b4b4, Ta5d6ff"Ta5d6ffreticulumTa5d6ff"Tb4b4b4) Tff7b72and Te6edf3appTff7b72.Td2a8ffreticulumTb4b4b4:
Te6edf3snr Tff7b72= Te6edf3appTff7b72.Td2a8ffreticulumTff7b72.Td2a8ffget_packet_snrTb4b4b4(Te6edf3receiptTff7b72.Td2a8ffproof_packetTff7b72.Td2a8ffpacket_hashTb4b4b4)
T8b949e# get signal quality
Te6edf3quality Tff7b72= Te6edf3receiptTff7b72.Td2a8ffproof_packetTff7b72.Td2a8ffq
Tff7b72if Te6edf3quality Tff7b72is Tff7b72None Tff7b72and Tffa657hasattrTb4b4b4(Te6edf3appTb4b4b4, Ta5d6ff"Ta5d6ffreticulumTa5d6ff"Tb4b4b4) Tff7b72and Te6edf3appTff7b72.Td2a8ffreticulumTb4b4b4:
Te6edf3quality Tff7b72= Te6edf3appTff7b72.Td2a8ffreticulumTff7b72.Td2a8ffget_packet_qTb4b4b4(Te6edf3receiptTff7b72.Td2a8ffproof_packetTff7b72.Td2a8ffpacket_hashTb4b4b4)
T8b949e# get and format round trip time
Te6edf3rtt Tff7b72= Te6edf3receiptTff7b72.Td2a8ffget_rttTb4b4b4(Tb4b4b4)
Te6edf3rtt_milliseconds Tff7b72= Tffa657roundTb4b4b4(Te6edf3rtt Tff7b72* T79c0ff1000Tb4b4b4, T79c0ff3Tb4b4b4)
Te6edf3rtt_duration_string Tff7b72= Ta5d6fffTa5d6ff"Tffd700{Te6edf3rtt_millisecondsTffd700}Ta5d6ff msTa5d6ff"
T8b949e# resend any previously failed messages to this destination now that path is available
Tff7b72for Te6edf3_ctx Tff7b72in Tffa657listTb4b4b4(Te6edf3appTff7b72.Td2a8ffcontextsTff7b72.Td2a8ffvaluesTb4b4b4(Tb4b4b4)Tb4b4b4)Tb4b4b4:
Tff7b72if Tb4b4b4(
Te6edf3_ctxTff7b72.Td2a8ffrunning
Tff7b72and Te6edf3_ctxTff7b72.Td2a8ffconfigTff7b72.Td2a8ffauto_resend_failed_messages_when_announce_receivedTff7b72.Td2a8ffgetTb4b4b4(Tb4b4b4)
Tb4b4b4)Tb4b4b4:
Te6edf3AsyncUtilsTff7b72.Td2a8ffrun_asyncTb4b4b4(
Te6edf3appTff7b72.Td2a8ffresend_failed_messages_for_destinationTb4b4b4(
Te6edf3destination_hash_strTb4b4b4,
Te6edf3contextTff7b72=Te6edf3_ctxTb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffmessageTa5d6ff"Tb4b4b4: Ta5d6fffTa5d6ff"Ta5d6ffValid reply from Tffd700{Te6edf3receiptTff7b72.Td2a8ffdestinationTff7b72.Td2a8ffhashTff7b72.Td2a8ffhexTb4b4b4(Tb4b4b4)Tffd700}Tffea00\nTa5d6ffDuration: Tffd700{Te6edf3rtt_duration_stringTffd700}Tffea00\nTa5d6ffHops There: Tffd700{Te6edf3hops_thereTffd700}Tffea00\nTa5d6ffHops Back: Tffd700{Te6edf3hops_backTffd700}Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffping_resultTa5d6ff"Tb4b4b4: Tb4b4b4{
Ta5d6ff"Ta5d6ffrttTa5d6ff"Tb4b4b4: Te6edf3rttTb4b4b4,
Ta5d6ff"Ta5d6ffhops_thereTa5d6ff"Tb4b4b4: Te6edf3hops_thereTb4b4b4,
Ta5d6ff"Ta5d6ffhops_backTa5d6ff"Tb4b4b4: Te6edf3hops_backTb4b4b4,
Ta5d6ff"Ta5d6ffrssiTa5d6ff"Tb4b4b4: Te6edf3rssiTb4b4b4,
Ta5d6ff"Ta5d6ffsnrTa5d6ff"Tb4b4b4: Te6edf3snrTb4b4b4,
Ta5d6ff"Ta5d6ffqualityTa5d6ff"Tb4b4b4: Te6edf3qualityTb4b4b4,
Ta5d6ff"Ta5d6ffreceiving_interfaceTa5d6ff"Tb4b4b4: Tffa657strTb4b4b4(
Te6edf3receiptTff7b72.Td2a8ffproof_packetTff7b72.Td2a8ffreceiving_interfaceTb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
T8b949e# get path table
Tf0883e@routesTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/path-tableTa5d6ff"Tb4b4b4)
Tf0883e@routesTff7b72.Td2a8ffpostTb4b4b4(Ta5d6ff"Ta5d6ff/api/v1/path-tableTa5d6ff"Tb4b4b4)
Tff7b72async Tff7b72def Td2a8ffpath_tableTb4b4b4(Te6edf3requestTb4b4b4)Tb4b4b4:
Te6edf3limit Tff7b72= Te6edf3requestTff7b72.Td2a8ffqueryTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6fflimitTa5d6ff"Tb4b4b4, Tff7b72NoneTb4b4b4)
Te6edf3offset Tff7b72= Te6edf3requestTff7b72.Td2a8ffqueryTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffoffsetTa5d6ff"Tb4b4b4, Tff7b72NoneTb4b4b4)
Te6edf3destination_hashes Tff7b72= Tff7b72None
Tff7b72if Te6edf3requestTff7b72.Td2a8ffmethod Tff7b72== Ta5d6ff"Ta5d6ffPOSTTa5d6ff"Tb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3body Tff7b72= Tff7b72await Te6edf3requestTff7b72.Td2a8ffjsonTb4b4b4(Tb4b4b4)
Te6edf3destination_hashes Tff7b72= Te6edf3bodyTff7b72.Td2a8ffgetTb4b4b4(Ta5d6ff"Ta5d6ffdestination_hashesTa5d6ff"Tb4b4b4)
Tff7b72if Te6edf3destination_hashes Tff7b72and Tff7b72not Tffa657isinstanceTb4b4b4(Te6edf3destination_hashesTb4b4b4, Tffa657listTb4b4b4)Tb4b4b4:
Te6edf3destination_hashes Tff7b72= Tff7b72None
Tff7b72except Tf85149ExceptionTb4b4b4:
Tff7b72pass
Te6edf3all_paths Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72if Tffa657hasattrTb4b4b4(Te6edf3appTb4b4b4, Ta5d6ff"Ta5d6ffreticulumTa5d6ff"Tb4b4b4) Tff7b72and Te6edf3appTff7b72.Td2a8ffreticulumTb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3all_paths Tff7b72= Te6edf3appTff7b72.Td2a8ffreticulumTff7b72.Td2a8ffget_path_tableTb4b4b4(Tb4b4b4)
Tff7b72except Tf85149ExceptionTb4b4b4:
Tff7b72pass
Tff7b72if Te6edf3destination_hashesTb4b4b4:
Te6edf3hash_set Tff7b72= Tb4b4b4{Te6edf3hTff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4) Tff7b72for Te6edf3h Tff7b72in Te6edf3destination_hashes Tff7b72if Tffa657isinstanceTb4b4b4(Te6edf3hTb4b4b4, Tffa657strTb4b4b4)Tb4b4b4}
Te6edf3all_paths Tff7b72= Tb4b4b4[Te6edf3p Tff7b72for Te6edf3p Tff7b72in Te6edf3all_paths Tff7b72if Te6edf3pTb4b4b4[Ta5d6ff"Ta5d6ffhashTa5d6ff"Tb4b4b4]Tff7b72.Td2a8ffhexTb4b4b4(Tb4b4b4)Tff7b72.Td2a8fflowerTb4b4b4(Tb4b4b4) Tff7b72in Te6edf3hash_setTb4b4b4]
Te6edf3total_count Tff7b72= Tffa657lenTb4b4b4(Te6edf3all_pathsTb4b4b4)
T8b949e# apply pagination if requested
Tff7b72if Te6edf3limit Tff7b72is Tff7b72not Tff7b72None Tff7b72or Te6edf3offset Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3start Tff7b72= Tffa657intTb4b4b4(Te6edf3offsetTb4b4b4) Tff7b72if Te6edf3offset Tff7b72else T79c0ff0
Te6edf3end Tff7b72= Tb4b4b4(Te6edf3start Tff7b72+ Tffa657intTb4b4b4(Te6edf3limitTb4b4b4)Tb4b4b4) Tff7b72if Te6edf3limit Tff7b72else Te6edf3total_count
Te6edf3paginated_paths Tff7b72= Te6edf3all_pathsTb4b4b4[Te6edf3startTb4b4b4:Te6edf3endTb4b4b4]
Tff7b72except Tb4b4b4(Tf85149ValueErrorTb4b4b4, Tf85149TypeErrorTb4b4b4)Tb4b4b4:
Te6edf3paginated_paths Tff7b72= Te6edf3all_paths
Tff7b72elseTb4b4b4:
Te6edf3paginated_paths Tff7b72= Te6edf3all_paths
Te6edf3path_table Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72for Te6edf3path Tff7b72in Te6edf3paginated_pathsTb4b4b4:
Te6edf3pathTb4b4b4[Ta5d6ff"Ta5d6ffhashTa5d6ff"Tb4b4b4] Tff7b72= Te6edf3pathTb4b4b4[Ta5d6ff"Ta5d6ffhashTa5d6ff"Tb4b4b4]Tff7b72.Td2a8ffhexTb4b4b4(Tb4b4b4)
Te6edf3pathTb4b4b4[Ta5d6ff"Ta5d6ffviaTa5d6ff"Tb4b4b4] Tff7b72= Te6edf3pathTb4b4b4[Ta5d6ff"Ta5d6ffviaTa5d6ff"Tb4b4b4]Tff7b72.Td2a8ffhexTb4b4b4(Tb4b4b4)
Te6edf3path_tableTff7b72.Td2a8ffappendTb4b4b4(Te6edf3pathTb4b4b4)
Tff7b72return Te6edf3webTff7b72.Td2a8ffjson_responseTb4b4b4(
Tb4b4b4{
Ta5d6ff"Ta5d6ffpath_tableTa5d6ff"Tb4b4b4: Te6edf3path_tableTb4b4b4,
Ta5d6ff"Ta5d6fftotal_countTa5d6ff"Tb4b4b4: Te6edf3total_countTb4b4b4,
Tb4b4b4}Tb4b4b4,
Tb4b4b4)
T8b949e# send lxmf message
──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────